import { IContextDescriptionItem } from '@/apis/chat/interfaces'
import { B2D, D2B } from '@/utils/binaryConvert'
import { getHasNameObjects } from '@/utils/getHasNameObjects'
import { Flow } from '@leafer-in/flow'
import { ElMessageBox } from 'element-plus'
import { Group, IUI, Text } from 'leafer-ui'
import { ref } from 'vue'
import { IConfig, IRegsKey } from '../interfaces'
import { generateNeicunItem } from './generateNeicunItem'
import uiJson from './ui.json'
import preData from './pre'

export const board = new Group({
    x: 0,
    y: 0,
})

board.add(uiJson.children as IUI[])

const uiItems = getHasNameObjects(board)

const codesToCodesArr = (codes: string) => {
    let arr = codes.split('\n')
    let res: string[][] = []
    for (const it of arr) {
        if (it.replace(/#.*/g, '').trim() === '') {
            continue
        }
        res.push(it.trim().split(' '))
    }
    return res
}

// 配置，从外部配置
const config = {
    addLen: preData[0].addLen, // 地址位数
    dataSize: preData[0].dataSize, // 内存中数据区域的长度
    codeStart: preData[0].codeStart, // 代码区域的开始位置
    codes: preData[0].codes, // 代码
    codesArr: codesToCodesArr(preData[0].codes),
}
const ram = new Array(2 ** config.addLen).fill('0')

// 寄存器
const regs = {
    R0: 0,
    R1: 0,
    R2: 0,
    R3: 0,
    set(name: IRegsKey, value: number) {
        this[name] = +value
        ;(uiItems[name.toLocaleLowerCase()] as Text).text = value.toString()
    },
}
// 内存的原始颜色
let neicunBg: string[] = []
// highlight内存
const highlightNeicun = (addr: number) => {
    uiItems.neicun.children!.forEach((it, index) => {
        it.children![1].fill = neicunBg[index]
        if (index === addr) {
            it.children![1].fill = '#70ad47'
        }
    })
}
// PC
const PC = {
    value: config.codeStart,
    set(value: number) {
        // 设置值
        this.value = value
        // 更新ui
        ;(uiItems.pc as Text).text = `初始值：${D2B(value, config.addLen)}`
        const y = 24 * value + uiItems.neicun.y!
        uiItems.pcArrow.animate(
            { y },
            {
                duration: 0.1,
            }
        )
        highlightNeicun(value)
    },
}
// G标志
let flagG = 0
// 正在运行
export const running = ref(false)
// 正在输入
export const inputing = ref(false)
// 状态信息
export const statusMsg = ref('机器尚未运行')

// 初始化
const init = (config1: IConfig) => {
    // 把代码渲染到内存中
    ;(uiItems.neicun as Flow).clear()
    neicunBg = []
    const { codesArr, codeStart, addLen } = config1
    const ramLength = 2 ** addLen
    for (let i = 0; i < ramLength; i++) {
        if (i < codeStart || i >= codesArr!.length + codeStart) {
            ram[i] = '0'
        } else {
            ram[i] = codesArr![i - codeStart].join(' ').replace(/#.*/g, '')
        }
        let color = '#add8e6' // 代码的颜色
        if (i < codeStart) {
            color = '#fafad2' // 数据的颜色
        }
        uiItems.neicun.add(generateNeicunItem(D2B(i, addLen), ram[i], color))
        neicunBg.push(color)
    }

    // 初始化寄存器
    regs.set('R0', 0)
    regs.set('R1', 0)
    regs.set('R2', 0)
    regs.set('R3', 0)

    // 初始化PC
    PC.set(codeStart)

    // 初始化G标志
    flagG = 0

    // 初始化状态信息
    statusMsg.value = '机器尚未运行'

    // 初始化运行状态
    running.value = false

    // 初始化输入状态
    inputing.value = false

    // 初始化输出
    ;(uiItems.output as Text).text = ''
}

init(config)

// 更新配置
export const updateConfig = (newConfig: IConfig) => {
    config.addLen = newConfig.addLen
    config.dataSize = newConfig.dataSize
    config.codeStart = newConfig.codeStart
    config.codes = newConfig.codes
    config.codesArr = codesToCodesArr(newConfig.codes)
    init(config)
}

// 关机
export const end = () => {
    running.value = false
    statusMsg.value = `运行结束，已停机`
}

// 开机运行
export const start = () => {
    init(config)
    running.value = true
    statusMsg.value = `运行中，即将运行指令 ${ram[PC.value]}`
}

// 验证一个寄存器名或者内存地址
const check = {
    reg(addr: string) {
        return ['R0', 'R1', 'R2', 'R3'].includes(addr)
    },
    ram(addr: string) {
        return B2D(addr) < ram.length
    },
    all(addr: string) {
        if (addr.length === 2) {
            return this.reg(addr)
        } else if (addr.length === config.addLen) {
            return this.ram(addr)
        } else {
            return false
        }
    },
}
// 指令处理函数集
const handlers: any = {
    in: {
        async run(curr: any) {
            const name1 = curr[1]
            if (!check.reg(name1)) {
                return `Error：${name1} 不是一个有效的寄存器地址`
            }
            // 输入函数
            inputing.value = true
            statusMsg.value = '正在等待输入'
            return await new Promise((resolve) => {
                ElMessageBox.prompt('请输入数字', '输入', {
                    confirmButtonText: 'OK',
                    closeOnClickModal: false,
                    showClose: false,
                    showCancelButton: false,
                })
                    .then(({ value }) => {
                        const num = +value
                        if (isNaN(num)) {
                            resolve(
                                `Error：运行指令 in 时发生异常，输入的 ${value} 不是一个数字`
                            )
                        }
                        regs.set(name1, num)
                        inputing.value = false
                        resolve('ok')
                    })
                    .catch(() => {})
            })
        },
    },
    mova: {
        run(curr: any) {
            // 把寄存器R2的值赋值给R1
            const name1 = curr[1] as IRegsKey
            const name2 = curr[2] as IRegsKey
            if (!check.reg(name1)) {
                return `Error：${name1} 不是一个有效的寄存器地址`
            }
            if (!check.reg(name2)) {
                return `Error：${name2} 不是一个有效的寄存器地址`
            }
            regs.set(name1, regs[name2])
            return 'ok'
        },
    },
    movb: {
        run(curr: any) {
            // 把寄存器R2的值赋值给地址为R0的内存
            const name1 = curr[1] as IRegsKey
            const name2 = curr[2] as IRegsKey
            if (!check.reg(name1)) {
                return `Error：${name1} 不是一个有效的寄存器地址`
            }
            if (!check.reg(name2)) {
                return `Error：${name2} 不是一个有效的寄存器地址`
            }
            ram[regs[name1]] = regs[name2]
            return 'ok'
        },
    },
    movc: {
        run(curr: any) {
            // 把地址为R0的内存值赋值给R1
            const name1 = curr[1] as IRegsKey
            const name2 = curr[2] as IRegsKey
            if (!check.reg(name1)) {
                return `Error：${name1} 不是一个有效的寄存器地址`
            }
            if (!check.reg(name2)) {
                return `Error：${name2} 不是一个有效的寄存器地址`
            }
            regs.set(name1, ram[regs[name2]])
            return 'ok'
        },
    },
    movd: {
        run() {
            // 把PC的值复制给寄存器R3
            regs.set('R3', PC.value)
            return 'ok'
        },
    },
    add: {
        run(curr: any) {
            let name1 = curr[1] as IRegsKey
            let name2 = curr[2] as IRegsKey
            if (!check.reg(name1)) {
                return `Error：${name1} 不是一个有效的寄存器地址`
            }
            if (!check.reg(name2)) {
                return `Error：${name2} 不是一个有效的寄存器地址`
            }
            regs.set(name1, regs[name1] + regs[name2])
            return 'ok'
        },
    },
    sub: {
        run(curr: any) {
            let name1 = curr[1] as IRegsKey
            let name2 = curr[2] as IRegsKey

            if (!check.reg(name1)) {
                return `Error：${name1} 不是一个有效的寄存器地址`
            }
            if (!check.reg(name2)) {
                return `Error：${name2} 不是一个有效的寄存器地址`
            }

            let res = (regs[name1] = regs[name1] - regs[name2])
            if (res > 0) {
                flagG = 1
            } else {
                flagG = 0
            }
            return 'ok'
        },
    },
    jmp: {
        run(curr: any) {
            let name2 = curr[2] as IRegsKey
            if (!check.reg(name2)) {
                return `Error：${name2} 不是一个有效的寄存器地址`
            }
            PC.set(regs[name2])
            return 'ok'
        },
    },
    jg: {
        run() {
            if (flagG >= 1) {
                PC.set(regs['R3'] - 1)
            }
            return 'ok'
        },
    },
    out: {
        run(curr: any) {
            let name = curr[1] as IRegsKey
            if (!check.reg(name)) {
                return `Error：${name} 不是一个有效的寄存器地址`
            }
            // ioOutput.value += regs[name]
            ;(uiItems.output as Text).text += regs[name].toString()
            return 'ok'
        },
    },
    movi: {
        run(curr: any) {
            let val = +curr[1]
            if (isNaN(val)) {
                return `Error：运行指令 ${curr.join(' ')} 时发生异常，${
                    curr[1]
                } 不是一个数字`
            }
            // regs['R0'] = val
            regs.set('R0', val)
            return 'ok'
        },
    },
    halt: {
        run() {
            end()
            return 'ok'
        },
    },
}

// 下一步函数，执行当前指向的指令
export const nextRun = async () => {
    // 判断指令是否存在

    let curr = ram[PC.value].split(/ |,/g).map((it: string) => it.trim())
    let res = ''
    if (handlers[curr[0]]) {
        res = await handlers[curr[0]].run(curr)
    } else {
        return 'error'
    }

    // 执行指令是否成功
    if (res !== 'ok') {
        return 'error'
    }

    let newPC = PC.value + 1
    // PC的值超出ram的长度
    if (PC.value >= 2 ** config.addLen) {
        newPC--
        PC.set(newPC)
        // end()
        return 'ok'
    }
    PC.set(newPC)

    // 已停机
    if (!running.value) {
        return 'ok'
    }

    statusMsg.value = `即将运行指令 ${ram[PC.value]}`

    return 'ok'
}

// 一步到位
export const oneStep = async () => {
    let res = ''
    while (res !== 'error' && running.value) {
        await new Promise((resolve) => {
            setTimeout(async () => {
                res = await nextRun()
                resolve(true)
            }, 200)
        })
    }
}

// 获取ai询问时的上下文
export const getContextDescription: () => IContextDescriptionItem[] = () => {
    return [
        {
            key: 'caseTitle',
            value: 'hnuvm原型机',
        },
        {
            key: 'caseDescription',
            value: 'hnuvm原型机是一个简单的虚拟机，用于教学案例，拥有cpu、内存、寄存器、指令集等基本功能',
        },
        {
            key: 'caseStatusInfo',
            value: `
pc的值为：${D2B(PC.value, config.addLen)}

内存内容：
| 地址 | 内容 |
| ---- | ---- |
${ram.map((it, index) => `| ${D2B(index, config.addLen)} | ${it} |`).join('\n')}

寄存器内容：
    R0：${regs.R0}
    R1：${regs.R1}
    R2：${regs.R2}
    R3：${regs.R3}

指令集：
汇编符号	功能
MOVA R1, R2	(R2)→R1
MOVB M, R2	(R2)→(R0)
MOVC R1, M	((R0))→R1	
MOVD R3, PC	(PC)→R3
ADD R1, R2	(R1)+(R2)→R1
SUB R1, R2	(R1)-(R2)→R1, IF(R1>R2), THEN G=1, ELSE G=0
JMP	(R3)→PC
JG	IF G=1, THEN (R3)→PC
IN R1	将常数赋给R1，将用户输入的值赋给R1
OUT R2	将R2的值输出
MOVI IMM	立即数IMM (R0)
HALT	停机
`,
        },
    ]
}
